/*
 * ExecutionExplorer.h
 * VB Script Analyzer
 * @author Gregoire JACOB (gregoire.jacob@orange-ftgroup.com)
 * @date 21/01/2008
 * @version 1.0
 * Simulate the script execution and analyse the different calls
 * to monitored functions as well as their arguments
 */

#include ".\Includes\Analyzer.h"


void printLogEntry(FILE * logf, struct TYPING * types,
				   unsigned long operation, int obj1, int obj2){
	unsigned long data = 0;

	//Logging operations according to desired format
	if(!operation) return;
	//Operation
	if(textual){
		switch(operation){
			case OP_STOP:
				fprintf(logf,"Stop;\n");
				return;
			case OP_OPEN:
				fprintf(logf,"Open ");
				break;
			case OP_CREA:
				fprintf(logf,"Create ");
				break;
			case OP_CLOS:
				fprintf(logf,"Close ");
				break;
			case OP_DEL:
				fprintf(logf,"Delete ");
				break;
			case OP_READ:
				fprintf(logf,"Read ");
				break;
			case OP_WRITE:
				fprintf(logf,"Write ");
				break;
			case OP_AFF:
				break;
			case L_LOOP:
				fprintf(logf,"(\n");
				return;
			case R_LOOP:
				fprintf(logf,")*\n");
				return;
			case L_COND:
				fprintf(logf,"{\n");
				return;
			case M_COND:
				fprintf(logf,"|\n");
				return;
			case R_COND:
				fprintf(logf,"}\n");
				return;
		}
	}
	if(!textual){
		data = operation;
		fwrite(&data,sizeof(long),1,logf);
	}
	if(operation==L_LOOP || operation==R_LOOP || operation==L_COND ||
		operation==M_COND || operation==R_COND || operation==OP_STOP) return; 
	//1st argument
	if(textual){fprintf(logf,"%s%d",typestr[getObjectType(types,obj1)],obj1);
	}else{
		data = typebin[getObjectType(types,obj1)];
		fwrite(&data,sizeof(long),1,logf);
		data = obj1;
		fwrite(&data,sizeof(long),1,logf);
	}
	//2nd argument
	if(operation == OP_READ){
		if(textual){fprintf(logf," <- %s%d",typestr[getObjectType(types,obj2)],obj2);
		}else{
			data = typebin[getObjectType(types,obj2)];
			fwrite(&data,sizeof(long),1,logf);
			data = obj2;
			fwrite(&data,sizeof(long),1,logf);
		}
	}else if(operation == OP_WRITE){
		if(textual){fprintf(logf," -> %s%d",typestr[getObjectType(types,obj2)],obj2);
		}else{
			data = typebin[getObjectType(types,obj2)];
			fwrite(&data,sizeof(long),1,logf);
			data = obj2;
			fwrite(&data,sizeof(long),1,logf);
		}
	}else if(operation == OP_AFF){
		if(textual){fprintf(logf," := %s%d",typestr[getObjectType(types,obj2)],obj2);
		}else{
			data = typebin[getObjectType(types,obj2)];
			fwrite(&data,sizeof(long),1,logf);
			data = obj2;
			fwrite(&data,sizeof(long),1,logf);
		}
	}
	//End operation
	if(textual) fprintf(logf,";\n");
}


int possiblyImbricated(char * name){
	int test = 0;
	test |= !strcasecmp(name,WRITEF1);
	test |= !strcasecmp(name,WRITEF2);
	test |= !strcasecmp(name,WRITEF3);
	test |= !strcasecmp(name,READF1);
	test |= !strcasecmp(name,READF2);
	test |= !strcasecmp(name,READF3);
	test |= !strcasecmp(name,READDOC);
	test |= !strcasecmp(name,WRITER1);
	test |= !strcasecmp(name,READR1);
	test |= !strcasecmp(name,READR2);
	test |= !strcasecmp(name,READR3);
	return test;
}

void processExpression(FILE * logf, struct SCRIPT * script, struct TYPING * types, 
					   unsigned long location, struct LINE * line,	
					   int tokenindex, int nature, char token[TOKENSIZE], int * next){
	char * tokens = (char *) calloc(TOKENMAXNB*TOKENSIZE,sizeof(char));
	char * stataccess = (char *) calloc(2*TOKENSIZE,sizeof(char));
	char * args = (char *) calloc(TOKENSIZE,sizeof(char));
	int nbtokens, i, obj;
	int type, hightype = 0; int unknown = 1;
	char * wsc = NULL, * attr = NULL;
	
	memset(token,0,TOKENSIZE);
	nbtokens = decomposeLine(line->line,tokens,TOKENMAXNB,TOKENSIZE);
	
	//Missing expression (may be on a next line)
	if(tokenindex>=nbtokens){
		strcpy_s(token,TOKENSIZE,"\"MissingToken\"");
		isMissing = 1;
		return;
	}

	strncpy_s(token,TOKENSIZE,ACCESS(tokens,tokenindex),TOKENSIZE-1);
	for(i=tokenindex; i<nbtokens;){
		
		//Imbricated call (manager.call(args))
		if(script&&possiblyImbricated(ACCESS(tokens,i+1))){
			struct LINE imbricated;
			static int resid = 25;
			char res[TOKENSIZE];
			//Forge a fake line to parse with an intermediate value for storage
			char * imbline = strcasestr((char*)(line->line+2),
												ACCESS(tokens,i));
			if(imbline){
			sprintf_s(res,TOKENSIZE,"INT%08X",resid); resid++;
			sprintf_s(imbricated.line,LINE_LENGTH,"%s = ",res);
			strcat_s(imbricated.line,LINE_LENGTH,imbline);
			//Analyze the intermediate line
			printf("[+] Imbricated call\n");
			processLine(logf,script,types,location,&imbricated);
			strcpy_s(ACCESS(tokens,i),TOKENSIZE,res);}
		}
		
		//Treat special folder
		if(!strcasecmp(ACCESS(tokens,i+1),"GetSpecialFolder")){
			sprintf_s(ACCESS(tokens,i+2),TOKENSIZE,"SpecialDir%d",*ACCESS(tokens,i+2));
			i+=2;
		}

		type = 0;
		obj = isKnownObject(types,ACCESS(tokens,i));
		if(obj>-1){//Object is known and maybe typed
			type = getObjectType(types,obj);
		}else{//Object can be typed
			type = ClassifyObject(ACCESS(tokens,i),&nature);
		}
		
		//Trace the highest typed object
		if(type>hightype){
			hightype = type;
			strncpy_s(token,TOKENSIZE,ACCESS(tokens,i),TOKENSIZE-1);
		}
		
		//If non typed and non string, replace by first known object or encountered string
		if(type==hightype){
			if(unknown && (obj >-1 ||
				(token[0]!='"' && ((char *)ACCESS(tokens,i))[0] == '"'))){
				if(obj>-1) unknown = 0;
				strncpy_s(token,TOKENSIZE,ACCESS(tokens,i),TOKENSIZE-1);
			}else{
				//Avoid unsignificant directory path for false negatives
				if(nature==OBJ_FILE&&!strncasecmp(token,"dir",3))
					strncpy_s(token,TOKENSIZE,ACCESS(tokens,i),TOKENSIZE-1);
			}
		}

		//Checks for static attributes 
		//(Document: body.createTextRange)
		//(Wscript: Fullname, ScriptFullname)
		//(Drive: DriveLetter, VolumeName, Path)
		strcpy_s(stataccess,2*TOKENSIZE,ACCESS(tokens,i)); 
		strcat_s(stataccess,2*TOKENSIZE,".");
		if(strcasestr(line->line,stataccess)){;i++;continue;}

		if(((char *)ACCESS(tokens,i+1))[0]!='&') break; //End of expression
		if(((char *)ACCESS(tokens,i+1))[1]!=0) break; //Case where & is part of the token
		i+=2;
	}//for
	if(next){*next=i+1;}

	free(tokens);
	free(stataccess);
	free(args);
}





void processLine(FILE * logf, struct SCRIPT * script, struct TYPING * types, 
				 unsigned long location, struct LINE * line){
	char * tokens = (char *) calloc(TOKENMAXNB*TOKENSIZE,sizeof(char));
	int nbtokens, i, j, index, storobj=-1, valobj=-1; int calldetected;
	
	//Detect system calls
	calldetected = monitorSytemCalls(logf,script,types,location,line);

	//Parse line
	nbtokens = decomposeLine(line->line,tokens,TOKENMAXNB,TOKENSIZE);
	
	for(i=0;i<nbtokens;i++){
		//Monitor string and processing and treat dependency			
		if(!strcasecmp(ACCESS(tokens,i),"Mid")
			||!strcasecmp(ACCESS(tokens,i),"Left")
			||!strcasecmp(ACCESS(tokens,i),"Ucase")
			||!strcasecmp(ACCESS(tokens,i),"Lcase")
			||!strcasecmp(ACCESS(tokens,i),"LTrim")
			||!strcasecmp(ACCESS(tokens,i),"RTrim")
			||!strcasecmp(ACCESS(tokens,i),"Replace")){
			int newstor = 0;
			int obj = isKnownObject(types,ACCESS(tokens,i+1));
			if(obj>-1 && i>=2 && ((char *)ACCESS(tokens,i-1))[0]=='='){
				int storobj = isKnownObject(types,ACCESS(tokens,i-2));
				if(storobj==-1){
					newstor = 1,
					storobj = addNewObject(types,NULL,getObjectNature(types,obj));
					addObjectReference(types,storobj,ACCESS(tokens,i-2));
					setObjectType(types,storobj,getObjectType(types,obj));
				}else{
					setObjectNature(types,storobj,getObjectNature(types,obj));
					setObjectType(types,storobj,getObjectType(types,obj));
				}
				if(newstor){strcpy_s(types->objects[storobj].ObjectName,
							NAME_MAX_LENGTH,types->objects[obj].ObjectName);}
				printLogEntry(logf, types, OP_AFF, storobj, obj);
			}
		}

		//Detect string proceclocal procedure and function calls
		index = isLocalProcedure(script,ACCESS(tokens,i));
		if(index>-1){
			//Avoid recursive calls
			//if((location&0xF0000000)==PROCLEVEL 
			//	&& index==(location&0x0FFFFFFF)){
			if(script->procedureslist[index].beingexecuted){
				printf("[+] Block recursive call to procedure %s\n",
						script->procedureslist[index].name);
			}else{
				script->procedureslist[index].beingexecuted = 1;
				//No return value, so can not be an affectation
				startProcedure(logf,script,types,index,line);
				script->procedureslist[index].beingexecuted = 0;
			}
			free(tokens); return;
		}else{
			index = isLocalFunction(script,ACCESS(tokens,i));
			if(index>-1){
				if(strcmp(ACCESS(tokens,i+1),"=")){//Avoid return values
					//Avoid recursive calls
					if(script->functionslist[index].beingexecuted){
						printf("[+] Block recursive call to function %s\n",
								script->functionslist[index].name);
					}else{
						script->functionslist[index].beingexecuted = 1;
						startFunction(logf,script,types,index,line);
						script->functionslist[index].beingexecuted = 0;
					}
					free(tokens); return;
				}else{
					line->type = AFFECTATION;
					updateReturnStorage(types, 
						script->functionslist[index].name, ACCESS(tokens,i+2));
					free(tokens); return;
				}//if call or return
			}
		}
	} if(calldetected) return;

	//Detect affectation of known object
	for(i=0;i<nbtokens;i++){
		if(((char *)ACCESS(tokens,i))[0]=='='||!strcasecmp(ACCESS(tokens,i),"in")){
			int maxobj = -1; int maxtype; int nullnat = 0;  int newstor = 0;
			int nbconselem; //Number of consecutive elements must
			int isarray = 0;//be < 2 except using & and array to concatenate
			
			//Either creation or retrieving of store object
			storobj = isKnownObject(types,ACCESS(tokens,i-1));
			if(storobj==-1){
				newstor = 1;
				storobj = addNewObject(types,NULL,0);
				addObjectReference(types,storobj,ACCESS(tokens,i-1));
			}//if unknown
			maxtype = getObjectType(types,storobj); 
			nbconselem = 0;

			//Look for significant passing value
			for(j=i+1;j<nbtokens;j++){
				if(!strcasecmp(ACCESS(tokens,j),"Array")){
					isarray = 1; j++;
				}//if
				if(((char *)ACCESS(tokens,j))[0]=='&'){
					nbconselem = 0;	
				}else{ 
					//Checks if access to a static attribute
					char stataccess[TOKENSIZE+5];
					strcpy_s(stataccess,5+TOKENSIZE,ACCESS(tokens,j));
					strcat_s(stataccess,5+TOKENSIZE,".");
					if(strcasestr(line->line,stataccess)){
						nbconselem = 0;
					}else{
						nbconselem++;
					}
				}//if
				if(!isarray && nbconselem>1) break;
				valobj = isKnownObject(types,ACCESS(tokens,j));
				if(valobj>-1){//known objects
					//Update store type when significant
					if(getObjectType(types,valobj)>maxtype){
						maxtype = getObjectType(types,valobj);
						maxobj = valobj;
					}
				}else if(ClassifyObject(ACCESS(tokens,j),&nullnat)>maxtype){//typed object
					maxobj = addNewObject(types,ACCESS(tokens,j),nullnat);
					maxtype = getObjectType(types,maxobj);
				}//if

			}//for
			if(maxobj>-1){
				line->type = AFFECTATION;
				setObjectType(types,storobj,getObjectType(types,maxobj));
				setObjectNature(types,storobj,getObjectNature(types,maxobj));
				if(newstor){strcpy_s(types->objects[storobj].ObjectName,
							NAME_MAX_LENGTH,types->objects[maxobj].ObjectName);}
				printLogEntry(logf, types, OP_AFF, storobj, maxobj);
			}
		}//if '=' found
	}//for
	free(tokens); 
}

int processLines(FILE * logf, struct SCRIPT * script, struct TYPING * types, 
				 unsigned long location, int lineindex){
	char * tokens = (char *) calloc(TOKENMAXNB*TOKENSIZE,sizeof(char));
	struct LINE * curline;
	int nbtokens, statement = 0;
	char expression[LINE_LENGTH]; char * exec; int strend;
	int strembedded = 0;
	
	//Parse line according to its location
	curline = accessLine(script,location,lineindex);
	if(strlen(curline->line)<=2) return lineindex+1;	//empty string
	if(curline->type==COMMENT) return lineindex+1;		//skip comment
	if(curline->type==MANAGER) return lineindex+1;		//skip manager declaration
	if(curline->type==DECLARATION) return lineindex+1;	//(declaration may require variable typing)....
	if(curline->type==MARKUP) return lineindex+1;

	//Missing token waited
	if(isMissing){
		int obj = isKnownObject(types,"MissingToken");
		isMissing = 0;
		processExpression(logf,script,types,location,curline,0,0,expression,NULL);
		types->objects[obj].ObjectName[0] = 0;
		if(expression[0]=='\"'){
			strcpy_s(types->objects[obj].ObjectName,NAME_MAX_LENGTH,expression);
		}else{
			addObjectAlias(types,obj,expression);
		}
	}

	//Checks for code embedded in string
	if(curline->line[0]=='\"'){
		strembedded = 1;
		curline->line[0] = ' ';
	}

	//Checks for execute statement
	exec = strcasestr(curline->line,"execute");
	if(exec&&exec<(curline->line+2)){
		//Look for the beginning of the expression
		while(*exec!='"'){
			exec++;
			if(exec>(curline->line+LINE_LENGTH)){
				free(tokens); return lineindex+1;}
		} exec++; 
		strcpy_s(expression,LINE_LENGTH,exec);
		strend = (int)strlen(expression);
		exec=&expression[strend-1];
		//Look for the end of the expression
		while(*exec!='"'){exec--;} 
		*exec='\n';exec++;*exec=0;
		printf("[+] Execute expression: %s",expression);
		strcpy_s(curline->line,LINE_LENGTH,expression);
	}

	nbtokens = decomposeLine(curline->line,(char*)tokens,TOKENMAXNB,TOKENSIZE);

	//Check if line is not beginning of a conditional
	if(!strcasecmp(ACCESS(tokens,0),"if")){
		statement = 1;
	}else if(!strcasecmp(ACCESS(tokens,0),"select")){ 
		statement = 2;
	}
	if(statement){
		printf("[+] Beginning a conditional statement:"); free(tokens);
		return processConditional(logf,script,types,location,lineindex,statement);
	}//if conditional
	
	//Check if line is not beginning of a loop
	if(!strcasecmp(ACCESS(tokens,0),"for")){
		statement = 1;
	}else if(!strcasecmp(ACCESS(tokens,0),"do")){ 
		statement = 2;
	}else if(!strcasecmp(ACCESS(tokens,0),"while")){ 
		statement = 3;
	}
	if(statement){
		printf("[+] Beginning a loop statement:"); free(tokens);
		return processLoop(logf,script,types,location,lineindex,statement);
	}//if loop

	//Otherwise independent line
	processLine(logf,script,types,location,curline);

	//Checks for code embedded in string
	if(strembedded){
		strembedded = 0;
		curline->line[0] = '\"';
	}
	free(tokens);
	return lineindex+1;
}

int processConditional(FILE * logf, struct SCRIPT * script, struct TYPING * types,
					   unsigned long location, int lineindex, int statement){
	char * thentag = NULL;
	struct LINE * curline, * nextline;
	struct LINE ifline, thenline;
	char * tokens = (char *) calloc(TOKENMAXNB*TOKENSIZE,sizeof(char));
	int i, nbtokens, maxpos, pos, elsefound, thenindex;

	maxpos = recoverMaximalPosition(script,location);

	//if...then...else/elseif...end if statement
	if(statement==1){
		printf(" if case\n");
		
		//Recover then position (if none considered at the end of first line)
		thenindex = lineindex-1;
		do{
			thenindex++;
			curline = accessLine(script,location,thenindex);
			thentag = strcasestr(curline->line,"then");			
			if(thenindex>=maxpos){//No then
				thenindex = lineindex;
				break;
			}
		}while(!thentag);
		
		//Parse conditions line
		for(i=lineindex;i<=thenindex;i++){		
			//Process condition (requires new line)
			curline = accessLine(script,location,i);
			ifline.type = 0;
			if(i==lineindex){//On if line skip if or elseif
				nbtokens = decomposeLine(curline->line,(char*)tokens,TOKENMAXNB,TOKENSIZE);
				strcpy_s(ifline.line,LINE_LENGTH,&(curline->line[strlen(ACCESS(tokens,0))])); 
			}else{
				strcpy_s(ifline.line,LINE_LENGTH,curline->line);
			}
			//Recover then position
			thentag = strcasestr(ifline.line,"then");
			if(thentag){thentag[0] = '\n'; thentag[1] = 0;}

			processLine(logf,script,types,location,&ifline);
		}
		lineindex = i;
		
		printLogEntry(logf, types, L_COND, 0, 0);
	
		//Process code blocks
		//One line conditional (requires newline)
		elsefound = 0;
		if(thentag&&strcasecmp(ACCESS(tokens,nbtokens-1),"then")){
			printf("%s\n",ACCESS(tokens,nbtokens-1));
			thenline.type = 0;
			strcpy_s(thenline.line,LINE_LENGTH,&thentag[5]); //skip then
			processLine(logf,script,types,location,&thenline);
			printf("[+] End of if conditional statement\n");
			printLogEntry(logf, types, M_COND, 0, 0);
			printLogEntry(logf, types, R_COND, 0, 0);
			return lineindex;
		}else{
		//Blocks on new lines, parse following ones
			pos = lineindex;	
			while(pos<maxpos){
				nextline = accessLine(script,location,pos);
				if(nextline->type==COMMENT){pos++; continue;}		//skip comment
				if(nextline->type==MANAGER){pos++; continue;}		//skip manager declaration
				if(nextline->type==DECLARATION){pos++; continue;}	//(declaration may require variable typing)....
				if(nextline->type==MARKUP){pos++; continue;}
				decomposeLine(nextline->line,(char*)tokens,TOKENMAXNB,TOKENSIZE);
				//Conditional structure
				if(strcasestr(nextline->line,"end if")){//end of conditional
					printf("[+] End of if conditional statement\n");
					if(!elsefound){printLogEntry(logf, types, M_COND, 0, 0);}
					printLogEntry(logf, types, R_COND, 0, 0);
					return pos+1;
				}else if(!strncasecmp(ACCESS(tokens,0),"elseif",6)){
					//printf("[+]Elseif\n");
					printLogEntry(logf, types, M_COND, 0, 0);
					return processConditional(logf,script,types,location,pos,1);
				}else if(!strncasecmp(ACCESS(tokens,0),"else",4)){
					//printf("[+]Else\n");
					elsefound = 1;
					printLogEntry(logf, types, M_COND, 0, 0);
					pos++;
				}else{
					pos = processLines(logf,script,types,location,pos);
				}
			}//while
		}//uni/multi line statement
	}//if type statement

	//select case...case...end select statement
	if(statement==2){
		printf(" select case\n");
		//Blocks on new lines, parse following ones
		pos = lineindex+2;//Skip first case statement
		while(pos<maxpos){
			nextline = accessLine(script,location,pos);
			if(nextline->type==COMMENT){pos++; continue;}		//skip comment
			if(nextline->type==MANAGER){pos++; continue;}		//skip manager declaration
			if(nextline->type==DECLARATION){pos++; continue;}	//(declaration may require variable typing)....
			if(nextline->type==MARKUP){pos++; continue;}
			decomposeLine(nextline->line,(char*)tokens,TOKENMAXNB,TOKENSIZE);
			//Conditional structure
			if(strcasestr(nextline->line,"end select")){//end of conditional
				printf("[+] End of select conditional statement\n");
				printLogEntry(logf, types, R_COND, 0, 0);
				return pos+1;
			}else if(!strncasecmp(ACCESS(tokens,0),"case",4)){
				//printf("[+]Case\n");
				printLogEntry(logf, types, M_COND, 0, 0);
				pos++;
			}else{
				pos = processLines(logf,script,types,location,pos);
			}
		}//while
	}//select statement

	free(tokens);
	return pos;
}

int processLoop(FILE * logf, struct SCRIPT * script, struct TYPING * types,
			    unsigned long location, int lineindex, int statement){
	struct LINE * nextline;
	char * tokens = (char *) calloc(TOKENMAXNB*TOKENSIZE,sizeof(char));
	char endtoken[5];
	int nbtokens, maxpos, pos;

	endtoken[0] = 0;
	//for to or for each...next statement
	switch(statement){
		case 1:
			printf(" for to/each case\n");
			strcat_s(endtoken,5,"next");
			break;
		case 2:
			printf(" do while/until case\n");
			strcat_s(endtoken,5,"loop");
			break;
		case 3:
			printf(" while case\n");
			strcat_s(endtoken,5,"wend");
	}//switch
	printLogEntry(logf, types, L_LOOP, 0, 0);

	//Process the line for calls into the statement
	processLine(logf,script,types,location,
		        accessLine(script,location,lineindex));

	//Blocks on new lines, parse following ones
	pos = lineindex+1;
	maxpos = recoverMaximalPosition(script,location);
	while(pos<maxpos){
		nextline = accessLine(script,location,pos);
		if(nextline->type==COMMENT){pos++; continue;}		//skip comment
		if(nextline->type==MANAGER){pos++; continue;}		//skip manager declaration
		if(nextline->type==DECLARATION){pos++; continue;}	//(declaration may require variable typing)....
		if(nextline->type==MARKUP){pos++; continue;}
		nbtokens = decomposeLine(nextline->line,(char*)tokens,TOKENMAXNB,TOKENSIZE);
		//Loop structure
		if(!strncasecmp(ACCESS(tokens,0),endtoken,4)){
			printf("[+] End of loop statement\n");
			printLogEntry(logf, types, R_LOOP, 0, 0);
			return pos+1;
		}else{
			pos = processLines(logf,script,types,location,pos);
		}
	}//while
	free(tokens);
	return pos;
}

/** Begin System call monitoring ************************************************************/
int monitorSytemCalls(FILE * logf, struct SCRIPT * script, struct TYPING * types, 
					   unsigned long location, struct LINE * line){
	char * tokens = (char *) calloc(TOKENMAXNB*TOKENSIZE,sizeof(char));
	int nbtokens, i;
	
	//Search for control operations
	if(monitorFileControl(logf,script,types,location,line)) return 1;
	if(monitorRegControl(logf,script,types,location,line)) return 1;
	if(monitorMailControl(logf,script,types,location,line)) return 1;
	//Search for input/output operations
	if(monitorFileIO(logf,script,types,location,line)) return 1;
	if(monitorRegIO(logf,script,types,location,line)) return 1;
	if(monitorMailIO(logf,script,types,location,line)) return 1;

	//Special folder (ignored in this version)
	if(strcasestr(line->line,".GetSpecialFolder")) return 1;
				
	//Parse line for script exit
	nbtokens = decomposeLine(line->line,(char*)tokens,TOKENMAXNB,TOKENSIZE);
	for(i=0;i<nbtokens;i++){
		//Script generic object
		if(isStaticScriptObject(ACCESS(tokens,i))>-1){
			if(!strcasecmp(ACCESS(tokens,i+1),STOP0)){
				line->type = SYSCALL;
				printLogEntry(logf, types, OP_STOP, 0, 0);
				return 1;
			}//if
		}
	}//for
	free(tokens);
	return 0;
}

int monitorFileControl(FILE * logf, struct SCRIPT * script, struct TYPING * types,
				unsigned long location, struct LINE * line){	   
	char tokens[TOKENMAXNB][TOKENSIZE]; char exp[TOKENSIZE]; int next = 1;
	static char driveobj[TOKENSIZE]; 
	static int drives = 0; static int driveset;
	int i, obj1, nbtokens, unknown = -1;
	struct LINE combined; static int combinnb = 45;
	char combinid[TOKENSIZE]; char * combinline;

	struct MANAG_ENTRY * localmanagers = accessManagers(script,location); 
	nbtokens = decomposeLine(line->line,(char*)tokens,TOKENMAXNB,TOKENSIZE);
	for(i=0;i<nbtokens;i++){
		
		unknown = isUnknownManager(&script->managers,tokens[i]);
		//File system manager
		if((isFileManager(&script->managers,tokens[i])>-1)
			|| (isFileManager(localmanagers,tokens[i])>-1)
			|| (unknown>-1)){
			
			//Open command
			if(!strcasecmp(tokens[i+1],OPENF1)//file
				|| !strcasecmp(tokens[i+1],OPENF2)
					|| !strcasecmp(tokens[i+1],OPENF3)){
				line->type = SYSCALL;
				processExpression(logf,script,types,location,
										   line,i+2,OBJ_FILE,exp,&next);
				obj1 = updateTypesAfterSysCall(types,exp,
													NULL,OBJ_FILE,OBJ_EXIST);
				printLogEntry(logf, types, OP_OPEN, obj1, 0);

				//Checks combined call
				combinline = strstr(line->line,tokens[next]);
				if((nbtokens-2>=next)&&combinline){
					char * found;
					combinline--;
					found = strchr(combinline,'.');
					if(!found){
						if(i>=2&&(tokens[i-1][0]=='='||!strcasecmp(tokens[i-1],"in")))
							addObjectReference(types,obj1,tokens[i-2]);
						if(unknown>1) //learn manager class
							addManagerObject(&script->managers,TFSO,tokens[i]);
						return 1;
					}
					sprintf_s(combinid,TOKENSIZE,"INT%08X",combinnb); combinnb++;
					addObjectReference(types,obj1,combinid);
					if(i>=2&&(tokens[i-1][0]=='='||!strcasecmp(tokens[i-1],"in"))){
						sprintf_s(combined.line,LINE_LENGTH,"%s = %s.%s",
							    tokens[i-2],combinid,found);
					}else{
						sprintf_s(combined.line,LINE_LENGTH,"%s.%s",combinid,found);
					}
					if(!monitorFileIO(logf,script,types,location,&combined)){
						removeObjectReference(types,obj1,combinid);
						if(i>=2&&(tokens[i-1][0]=='='||!strcasecmp(tokens[i-1],"in")))
							addObjectReference(types,obj1,tokens[i-2]);
					}
				}else{
					if(i>=2&&(tokens[i-1][0]=='='||!strcasecmp(tokens[i-1],"in")))
							addObjectReference(types,obj1,tokens[i-2]);
				}
				if(unknown>1) //learn manager class
					addManagerObject(&script->managers,TFSO,tokens[i]);
				return 1;

			//File existence command
			}else if(!strcasecmp(tokens[i+1],OPENFT)){
				line->type = SYSCALL;
				processExpression(logf,script,types,location,
										   line,i+2,OBJ_FILE,exp,NULL);
				obj1 = updateTypesAfterSysCall(types,exp,
													NULL,OBJ_FILE,OBJ_CREATED);
				printLogEntry(logf, types, OP_OPEN, obj1, 0);
				if(unknown>1) //learn manager class
					addManagerObject(&script->managers,TFSO,tokens[i]);
				return 1;

			//Drive commands
			}else if(!strcasecmp(tokens[i+1],OPEND1)){
			    line->type = SYSCALL;
				obj1 = updateTypesAfterSysCall(types,COM_DRIVE,
													tokens[i-2],OBJ_DRIVE,OBJ_EXIST);
				sprintf_s(types->objects[obj1].ObjectName, NAME_MAX_LENGTH,
													"Drive(ref:%s)",tokens[i-2]);
				printLogEntry(logf, types, OP_OPEN, obj1, 0);
				if(unknown>1) //learn manager class
					addManagerObject(&script->managers,TFSO,tokens[i]);
				return 1;
			}else if(!strcasecmp(tokens[i+1],OPEND2)){
				if((i+2<nbtokens&&!strcasecmp(tokens[i+2],"Item"))
					||(i-2>=0&&!strcasecmp(tokens[i-1],"In"))){
					line->type = SYSCALL;
					obj1 = updateTypesAfterSysCall(types,COM_DRIVE,
													tokens[i-2],OBJ_DRIVE,OBJ_EXIST);
					sprintf_s(types->objects[obj1].ObjectName, NAME_MAX_LENGTH,
													"Drive(ref:%s)",tokens[i-2]);
					printLogEntry(logf, types, OP_OPEN, obj1, 0);
				}else if(i-2>=0&&tokens[i-1][0]=='='){
					drives = 1;
					strcpy_s(driveobj,TOKENSIZE,tokens[i-2]);
					line->type = SYSCALL;
				}else{
					line->type = SYSCALL;
				}
				if(unknown>1) //learn manager class
					addManagerObject(&script->managers,TFSO,tokens[i]);
				return 1;
			}//if open
		
			//Creation command
			if(!strcasecmp(tokens[i+1],CREATEF2)
				|| !strcasecmp(tokens[i+1],CREATEF3)){
				line->type = SYSCALL;
				processExpression(logf,script,types,location,
					                       line,i+2,OBJ_FILE,exp,&next);
				obj1 = updateTypesAfterSysCall(types,exp,
													NULL,OBJ_FILE,OBJ_CREATED);
				printLogEntry(logf, types, OP_CREA, obj1, 0);

				//Checks combined call
				combinline = strstr(line->line,tokens[next]);
				if((nbtokens-2>=next)&&combinline){
					char * found = strchr(combinline,'.');
					if(!found){
						if(i>=2&&(tokens[i-1][0]=='='||!strcasecmp(tokens[i-1],"in")))
							addObjectReference(types,obj1,tokens[i-2]);
						if(unknown>1) //learn manager class
							addManagerObject(&script->managers,TFSO,tokens[i]);
						return 1;
					}
					sprintf_s(combinid,TOKENSIZE,"INT%08X",combinnb); combinnb++;
					addObjectReference(types,obj1,combinid);
					if(i>=2&&(tokens[i-1][0]=='='||!strcasecmp(tokens[i-1],"in"))){
						sprintf_s(combined.line,LINE_LENGTH,"%s = %s.%s",tokens[i-2],combinid,found);
					}else{
						sprintf_s(combined.line,LINE_LENGTH,"%s.%s",combinid,found);
					}
					if(!monitorFileIO(logf,script,types,location,&combined)){
						removeObjectReference(types,obj1,combinid);
						if(i>=2&&(tokens[i-1][0]=='='||!strcasecmp(tokens[i-1],"in")))
							addObjectReference(types,obj1,tokens[i-2]);
					}
				}else{
					if(i>=2&&(tokens[i-1][0]=='='||!strcasecmp(tokens[i-1],"in")))
							addObjectReference(types,obj1,tokens[i-2]);
				}
				if(unknown>1) //learn manager class
					addManagerObject(&script->managers,TFSO,tokens[i]);
				return 1;
			}//if creation
				
			//Delete command
			if(!strcasecmp(tokens[i+1],DELETEF1)
				|| !strcasecmp(tokens[i+1],DELETEF2)){
				line->type = SYSCALL;
				processExpression(logf,script,types,location,
					                       line,i+2,OBJ_FILE,exp,NULL);
				obj1 = updateTypesAfterSysCall(types,exp,
													tokens[i-2],OBJ_FILE,OBJ_EXIST);
				printLogEntry(logf, types, OP_DEL, obj1, 0);
				if(unknown>1) //learn manager class
					addManagerObject(&script->managers,TFSO,tokens[i]);
				return 1;
			}//if delete
		
		}//if file system manager

		//Drive set object 
		if(drives && !strcasecmp(driveobj,tokens[i])){
			if((i+1<nbtokens && (!strcasecmp(tokens[i+1],"Item")||
				!strcasecmp(tokens[i+1],"Files")))|| !strcasecmp(tokens[i-1],"in")){
				line->type = SYSCALL;
				obj1 = updateTypesAfterSysCall(types,COM_DRIVE,
											tokens[i-2],OBJ_DRIVE,OBJ_EXIST);
				sprintf_s(types->objects[obj1].ObjectName, NAME_MAX_LENGTH,
													"Drive(ref:%s)",tokens[i-2]);
				printLogEntry(logf, types, OP_OPEN, obj1, 0);
				return 1;
			}
		}//if drive set

		//Document object
		if((nbtokens-i>2) && !strcasecmp(tokens[i],"Document")){
			if(!strcasecmp(tokens[i+1],"Body")&&!strcasecmp(tokens[i+2],OPENDOC)){
				line->type = SYSCALL;
				obj1 = updateTypesAfterSysCall(types,HTM_DOC,
											NULL,OBJ_FILE,OBJ_EXIST);
				if(i>=2) addObjectReference(types,obj1,tokens[i-2]);
				setObjectStatus(types,obj1,OBJ_EXIST);
				printLogEntry(logf, types, OP_OPEN, obj1, 0);
				return 1;
			}
		}

		//Shell manager
		if((isShellManager(&script->managers,tokens[i])>-1)
			|| (isShellManager(localmanagers,tokens[i])>-1)){
			
			//Open command
			if(!strcasecmp(tokens[i+1],OPENRUN)){
				line->type = SYSCALL;
				processExpression(logf,script,types,location,
										   line,i+2,OBJ_FILE,exp,&next);
				obj1 = updateTypesAfterSysCall(types,exp,
													NULL,OBJ_FILE,OBJ_EXIST);
				printLogEntry(logf, types, OP_OPEN, obj1, 0);
				if(unknown>1) //learn manager class
					addManagerObject(&script->managers,TSHELL,tokens[i]);
				return 1;
			}
		}
	}//for
	return 0;
}

int monitorRegControl(FILE * logf, struct SCRIPT * script, struct TYPING * types,
				unsigned long location, struct LINE * line){	   
	char tokens[TOKENMAXNB][TOKENSIZE]; char exp[TOKENSIZE];
	int i, obj1, nbtokens, unknown = -1;
	
	struct MANAG_ENTRY * localmanagers = accessManagers(script,location);
	nbtokens = decomposeLine(line->line,(char*)tokens,40,255); 
	for(i=0;i<nbtokens;i++){

		unknown = isUnknownManager(&script->managers,tokens[i]);
		//Shell manager (registry)
		if((isShellManager(&script->managers,tokens[i])>-1)
				|| (isShellManager(localmanagers,tokens[i])>-1)
				|| unknown > -1){
					
			//Delete command 
			if(!strcasecmp(tokens[i+1],DELETER1)){
				line->type = SYSCALL;
				processExpression(logf,script,types,location,
					                       line,i+2,OBJ_REG,exp,NULL);
				obj1 = updateTypesAfterSysCall(types,exp,
													NULL,OBJ_REG,OBJ_EXIST);
				printLogEntry(logf, types, OP_DEL, obj1, 0);
				if(unknown>1) //learn manager class
					addManagerObject(&script->managers,TSHELL,tokens[i]);
				return 1;
			}//if delete
		
		}//if shell manager
	}//for
	return 0;
}

int monitorMailControl(FILE * logf, struct SCRIPT * script, struct TYPING * types,
					   unsigned long location, struct LINE * line){
	char tokens[TOKENMAXNB][TOKENSIZE];
	int i, obj1, nbtokens;

	struct MANAG_ENTRY * localmanagers = accessManagers(script,location); 
	nbtokens = decomposeLine(line->line,(char*)tokens,TOKENMAXNB,TOKENSIZE);
	for(i=0;i<nbtokens;i++){
		
		//Mail object 
		if(strcasestr(tokens[i],MAILOB1)||
			strcasestr(tokens[i],MAILOB2)){
			
			//Create command
			if(!strcasecmp(tokens[i-1],"CreateObject")){
				line->type = SYSCALL;
				if(tokens[i-2][0]=='='){
					obj1 = updateTypesAfterSysCall(types,tokens[i],
													tokens[i-3],OBJ_MAIL,OBJ_CREATED);
				}else{
					obj1 = updateTypesAfterSysCall(types,tokens[i],
													NULL,OBJ_MAIL,OBJ_CREATED);
				}
				printLogEntry(logf, types, OP_CREA, obj1, 0);
				return 1;
			}//if create
		}
		//Outlook mail object 
		if(isMailManager(localmanagers,tokens[i])>-1 ||
			isMailManager(&script->managers,tokens[i])>-1){
			//Creation command
			if(!strcasecmp(tokens[i+1],CREATEM1)){
				line->type = SYSCALL;
				obj1 = updateTypesAfterSysCall(types,"OutlookItem",
											   tokens[i-2],OBJ_MAIL,OBJ_CREATED);
				printLogEntry(logf, types, OP_CREA, obj1, 0);
				return 1;
			}//if creation
		}
	}
	return 0;
}

int monitorFileIO(FILE * logf, struct SCRIPT * script, struct TYPING * types,
				  unsigned long location, struct LINE * line){
	char tokens[TOKENMAXNB][TOKENSIZE]; char exp[TOKENSIZE];
	int i, obj1, obj2, next, nbtokens;

	nbtokens = decomposeLine(line->line,(char*)tokens,TOKENMAXNB,TOKENSIZE);
	for(i=0;i<nbtokens;i++){
		
		//Writing operations on file
		if(!strcasecmp(tokens[i],WRITEF1)
			|| !strcasecmp(tokens[i],WRITEF2)){
			obj1 = isKnownObject(types,tokens[i-1]);
			//Checks types consistency (file object)
			if((obj1>-1)&&((getObjectNature(types,obj1)==OBJ_FILE)
							||(getObjectNature(types,obj1)==OBJ_FOLD)
							||(getObjectNature(types,obj1)==OBJ_DRIVE))){
				line->type = SYSCALL;
				processExpression(logf,script,types,location,
					                       line,i+1,VAR,exp,NULL);
				obj2 = updateTypesAfterSysCall(types,exp,NULL,VAR,OBJ_CREATED);
				printLogEntry(logf, types, OP_WRITE, obj2, obj1);
			}else{
				printf("[-] Writing applied to invalid file object\n");
			}//if valid file object
			return 1;
		}else if(!strcasecmp(tokens[i],WRITEF4)
					|| !strcasecmp(tokens[i],WRITEF5)){
			obj1 = isKnownObject(types,tokens[i-1]);
			//Checks types consistency (file object)
			if((obj1>-1)&&((getObjectNature(types,obj1)==OBJ_FILE)
							||(getObjectNature(types,obj1)==OBJ_FOLD)
							||(getObjectNature(types,obj1)==OBJ_DRIVE))){
				line->type = SYSCALL;
				processExpression(logf,script,types,location,
					                       line,i+1,OBJ_FILE,exp,NULL);
				obj2 = updateTypesAfterSysCall(types,exp,NULL,OBJ_FILE,OBJ_CREATED);
				printLogEntry(logf, types, OP_WRITE, obj1, obj2);
			}else{
				printf("[-] Writing applied to invalid file object\n");
			}//if valid file object
			return 1;
		}//Writing case
		
		//Direct Writing operations on file (copyfile)
		if(!strcasecmp(tokens[i],WRITEF3)
			||!strcasecmp(tokens[i],WRITEF6)){
			//Checks for manager ignored
			processExpression(logf,script,types,location,
				                       line,i+1,OBJ_FILE,exp,&next);
			obj1 = updateTypesAfterSysCall(types,exp,NULL,OBJ_FILE,OBJ_CREATED);
			processExpression(logf,script,types,location,
				                       line,next,OBJ_FILE,exp,&next);
			obj2 = updateTypesAfterSysCall(types,exp,NULL,OBJ_FILE,OBJ_CREATED);
			line->type = SYSCALL;
			printLogEntry(logf, types, OP_WRITE, obj1, obj2);
			return 1;
		}//Direct Writing case

		//Reading operations on file
		if(!strcasecmp(tokens[i],READF1)
			|| !strcasecmp(tokens[i],READF2)
				|| !strcasecmp(tokens[i],READF3)
					|| !strcasecmp(tokens[i],READDOC)){
					obj1 = isKnownObject(types,tokens[i-1]);
					//Checks types consistency (file object)
					if((obj1>-1)&&((getObjectNature(types,obj1)==OBJ_FILE)
									||(getObjectNature(types,obj1)==OBJ_FOLD)
									||(getObjectNature(types,obj1)==OBJ_DRIVE))){
						if(tokens[i-2][0]=='='){
							obj2 = updateTypesAfterSysCall(types,tokens[i-3],NULL,VAR,OBJ_CREATED);
						}else if(tokens[i-3][0]=='='){
							obj2 = updateTypesAfterSysCall(types,tokens[i-4],NULL,VAR,OBJ_CREATED);
						}else{
							obj2 = updateTypesAfterSysCall(types,"unstored",NULL,VAR,OBJ_CREATED);
						}
						printLogEntry(logf, types, OP_READ, obj2, obj1);
					}else{
						printf("[-] Reading applied to invalid file object\n");
					}
					return 1;
		}//Reading case
	}//for
	return 0;
}

int monitorRegIO(FILE * logf, struct SCRIPT * script, struct TYPING * types,
				  unsigned long location, struct LINE * line){
	char tokens[TOKENMAXNB][TOKENSIZE]; char exp[TOKENSIZE];
	int i, obj1, obj2, indexp2, nbtokens, unknown = -1;
	
	struct MANAG_ENTRY * localmanagers = accessManagers(script,location); 
	nbtokens = decomposeLine(line->line,(char*)tokens,TOKENMAXNB,TOKENSIZE);
	for(i=0;i<nbtokens;i++){
		
		unknown = isUnknownManager(&script->managers,tokens[i]);
		//Shell manager (registry)
		if((isShellManager(&script->managers,tokens[i])>-1)
				|| (isShellManager(localmanagers,tokens[i])>-1)
				|| unknown > -1){
					
			//Write command 
			if(!strcasecmp(tokens[i+1],WRITER1)){
				line->type = SYSCALL;
				processExpression(logf,script,types,location,
					                        line,i+2,OBJ_REG,exp,&indexp2);
				obj1 = updateTypesAfterSysCall(types,exp,NULL,OBJ_REG,OBJ_CREATED);
				processExpression(logf,script,types,location,
					                        line,indexp2,VAR,exp,NULL);
				obj2 = updateTypesAfterSysCall(types,exp,NULL,VAR,OBJ_CREATED);	
				printLogEntry(logf, types, OP_WRITE, obj2, obj1);
				if(unknown>1) //learn manager class
					addManagerObject(&script->managers,TSHELL,tokens[i]);
				return 1;
			}//Write command

			//Read command
			if(!strcasecmp(tokens[i+1],READR1)){
				line->type = SYSCALL;
				obj1 = updateTypesAfterSysCall(types,tokens[i+2],NULL,OBJ_REG,OBJ_CREATED);					
				if(tokens[i-1][0] == '='&& i>=2){//if result is stored
					obj2 = updateTypesAfterSysCall(types,tokens[i-2],NULL,VAR,OBJ_CREATED);
					printLogEntry(logf, types, OP_READ, obj2, obj1);
				}
				if(unknown>1) //learn manager class
					addManagerObject(&script->managers,TSHELL,tokens[i]);
				return 1;
			}//Read command
		}//shell manager
	}//for
	return 0;
}



int monitorMailIO(FILE * logf, struct SCRIPT * script, struct TYPING * types,
				  unsigned long location, struct LINE * line){
	char tokens[TOKENMAXNB][TOKENSIZE]; char exp[TOKENSIZE];
	static char attachobj[TOKENSIZE]; 
	static int attached = 0; static int mailattobj;
	int i, objm, objv, nbtokens;

	nbtokens = decomposeLine(line->line,(char*)tokens,TOKENMAXNB,TOKENSIZE);
	for(i=0;i<nbtokens;i++){
		
		objm = isKnownObject(types,tokens[i]);
		//Mail object 
		if(objm>-1 && getObjectNature(types,objm)==OBJ_MAIL){
			
			//Write body command
			if(!strcasecmp(tokens[i+1],WRITEM1)||
				!strcasecmp(tokens[i+1],WRITEM2)){
				line->type = SYSCALL;
				processExpression(logf,script,types,location,
									       line,i+3,0,exp,NULL);
				objv = updateTypesAfterSysCall(types,exp,NULL,0,OBJ_CREATED);
				printLogEntry(logf, types, OP_WRITE, objv, objm);
				return 1;
			}//if write
			//Write attachment command
			if(!strcasecmp(tokens[i+1],WRITEM3)||
				!strcasecmp(tokens[i+1],WRITEM4)){
				line->type = SYSCALL;
				processExpression(logf,script,types,location,
					              line,i+2,0,exp,NULL);
				objv = updateTypesAfterSysCall(types,exp,NULL,0,OBJ_CREATED);
				printLogEntry(logf, types, OP_WRITE, objv, objm);
				return 1;
			}else if(!strcasecmp(tokens[i+1],WRITEM5)){
				if(i+2<nbtokens&&!strcasecmp(tokens[i+2],"add")){
					line->type = SYSCALL;
					processExpression(logf,script,types,location,
									  line,i+3,0,exp,NULL);
					objv = updateTypesAfterSysCall(types,exp,NULL,0,OBJ_CREATED);
					printLogEntry(logf, types, OP_WRITE, objv, objm);
					return 1;
				}else if(i-2>=0){
					attached = 1;
					mailattobj = objm;
					strcpy_s(attachobj,TOKENSIZE,tokens[i-2]);
					line->type = SYSCALL;
					return 1;
				}else{
					line->type = SYSCALL;
					return 1;
				}
			}//if write
		}//if Mail object

		//Attachment object 
		if(attached && !strcmp(attachobj,tokens[i]) &&
			i+2<nbtokens && !strcasecmp(tokens[i+1],"add")){
			line->type = SYSCALL;
			processExpression(logf,script,types,location,
				              line,i+2,0,exp,NULL);
			objv = updateTypesAfterSysCall(types,exp,NULL,0,OBJ_CREATED);
			printLogEntry(logf, types, OP_WRITE, objv, mailattobj);
			return 1;
		}//if attachment
	}//for
	return 0;
}

/** Begin Code emulation ********************************************************************/
void startFunction(FILE * logf, struct SCRIPT * script, 
				   struct TYPING * types, int funcindex, struct LINE * line){
	char * tokens = (char *) calloc(TOKENMAXNB*TOKENSIZE,sizeof(char));
	int parameters[10];
	char arguments[10][TOKENSIZE];
	int i, j, retobj, nbtokens, nbarg, nextparam, pos = 0;
	
	//Jump to function
	printf("[+] Jump inside function %s\n",
		script->functionslist[funcindex].name);
	//Merge parameters with local aliases from the signature
	nbarg = script->functionslist[funcindex].nbarg;
	nbtokens = decomposeLine(line->line,(char*)tokens,TOKENMAXNB,TOKENSIZE);
	for(i=0;i<nbtokens;i++){
		if(!strcasecmp(ACCESS(tokens,i),script->functionslist[funcindex].name)) break;
	}
	nextparam = i+1;
	for(j=1;j<=nbarg;j++){
		processExpression(logf,script,types,FUNCLEVEL|funcindex,
			              line,nextparam,0,arguments[j-1],&nextparam);
		parameters[j-1] = updateTypesBeforeLocCall(types, arguments[j-1], 
			              script->functionslist[funcindex].arguments[j-1]);
	}
	
	//Following the execution path
	while(pos<script->functionslist[funcindex].nblines){
		//Analyze code
		pos = processLines(logf,script,types,FUNCLEVEL|funcindex,pos);	
	}//while

	//Return from function
	printf("[+] Return from function %s\n",script->functionslist[funcindex].name);
	//Unmerge parameters with local aliases from the signature
	for(j=1;j<=nbarg;j++){
		removeObjectReference(types, parameters[j-1], 
			script->functionslist[funcindex].arguments[j-1]);
	}
	retobj = isKnownObject(types,script->functionslist[funcindex].name);
	if(retobj>-1){
		removeObjectReference(types,retobj,script->functionslist[funcindex].name);
		//If the return value is affected
		if(i>1 && ((char*)ACCESS(tokens,i-1))[0]== '='){
			addObjectReference(types,retobj,ACCESS(tokens,i-2));
		}//if affectation
	}
	free(tokens);
}

void startProcedure(FILE * logf, struct SCRIPT * script, 
					struct TYPING * types, int procindex, struct LINE * line){
	char * tokens = (char *) calloc(TOKENMAXNB*TOKENSIZE,sizeof(char));
	int parameters[ARG_MAX_NB];
	int arguments[ARG_MAX_NB][TOKENSIZE];
	int i, j, nbtokens, nbarg, nextparam, pos = 0;
	
	//Jump to procedure
	printf("[+] Jump inside procedure %s\n",
		script->procedureslist[procindex].name);
	//Merge parameters with local aliases from the signature
	nbarg = script->procedureslist[procindex].nbarg;
	nbtokens = decomposeLine(line->line,(char*)tokens,TOKENMAXNB,TOKENSIZE);
	for(i=0;i<nbtokens;i++){
		if(!strcasecmp(ACCESS(tokens,i),script->procedureslist[procindex].name)) break;
	}
	nextparam = i+1;
	for(j=1;j<=nbarg;j++){
		processExpression(logf,script,types,PROCLEVEL|procindex,
						  line,nextparam,0,arguments[j-1],&nextparam);
		parameters[j-1] = updateTypesBeforeLocCall(types, arguments[j-1], 
			              script->procedureslist[procindex].arguments[j-1]);
	}

	//Following the execution path
	while(pos<script->procedureslist[procindex].nblines){
		//Analyze code
		pos = processLines(logf,script,types,PROCLEVEL|procindex,pos);	
	}//while

	//Return from procedure
	printf("[+] Return from procedure %s\n",script->procedureslist[procindex].name);
	//Unmerge parameters with local aliases from the signature
	for(j=1;j<=nbarg;j++){
		removeObjectReference(types, parameters[j-1], 
			script->procedureslist[procindex].arguments[j-1]);
	}
	free(tokens);
}

void startMain(FILE * logf, struct SCRIPT * script, struct TYPING * types){
	int pos = 0;
	
	//Following the execution path
	while(pos<script->nblines){
		//Analyze code
		pos = processLines(logf,script,types,MAINLEVEL,pos);
	}//while
}
/** End Code emulation **********************************************************************/